package com.example.demo.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.demo.constant.CommonConstant;
import com.example.demo.entity.Information;
import com.example.demo.entity.User;
import com.example.demo.entity.UserSimple;
import com.example.demo.entity.vo.UserVo;
import com.example.demo.exception.bizException.BizException;
import com.example.demo.mapper.UserMapper;
import com.example.demo.service.*;
import com.example.demo.util.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
* <p>
*  服务实现类
* </p>
*
* @author cy
* @since 2020-08-01
*/
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private MailService mailService;

    @Autowired
    private InformationService informationService;

    @Autowired
    private UOperationService uOperationService;

    @Autowired
    private OperationService operationService;

    @Value("${web.upload-path}")
    private String path;

    @Override
    public Page<User> listUsersByPage(int page, int pageSize, String factor,Integer teamState,Integer firmState) {
        log.info("正在执行分页查询user: page = {} pageSize = {} factor = {} teamTag={} firmTag={}",page,pageSize,factor,teamState,firmState);
        QueryWrapper<User> queryWrapper =  new QueryWrapper<User>()
                //不查询密码字段
                .select(User.class, info->!info.getColumn().equals("password"))
                .orderByDesc("state").orderByDesc("team_state")
                .eq(teamState!=null,"team_state",teamState)
                .eq(firmState!=null,"firm_state",firmState)
                .and(factor.length()!=0,w->w.like("account", factor)
                        .or().like("phone",factor));
        Page<User> result = super.page(new Page<>(page, pageSize),queryWrapper);
        log.info("分页查询user完毕: 结果数 = {} ",result.getRecords().size());
        return result;
    }

    @Override
    public Page<UserSimple> adminListUsersByPage(int page, int pageSize, String factor, Integer teamState, Integer firmState) {
        log.info("正在执行分页查询user: page = {} pageSize = {} factor = {} teamTag={} firmTag={}",page,pageSize,factor,teamState,firmState);
        QueryWrapper<User> queryWrapper =  new QueryWrapper<User>()
                .select("user_id","account","state","photo","nickname","phone","mail","intro","team_state","firm_state")
                .orderByDesc("state").orderByDesc("team_state")
                .eq(teamState!=null,"team_state",teamState)
                .eq(firmState!=null,"firm_state",firmState)
                .and(factor.length()!=0,w->w.like("account", factor)
                        .or().like("phone",factor));
        Page<User> result = super.page(new Page<>(page, pageSize),queryWrapper);
        //转为uservo
        Page<UserSimple> userVo = new Page<>();
        List<UserSimple> userVoList = new ArrayList<>(result.getRecords().size());
        BeanUtils.copyProperties(result,userVo);
        for (User user:result.getRecords()) {
            UserSimple simple = new UserSimple(user);
            simple.setOperations(operationService.getOperationsByIds(uOperationService.getUOperationByUId(user.getUserId())));
            userVoList.add(simple);
        }
        userVo.setRecords(userVoList);
        log.info("分页查询user完毕: 结果数 = {} ",result.getRecords().size());
        return userVo;
    }

    @Override
    public User getUserById(int id) {
        log.info("正在查询user中id为{}的数据",id);
        User user = super.getById(id);
        user.setPassword(null);
        log.info("查询id为{}的user{}",id,(null == user?"无结果":"成功"));
        return user;
    }

    @Override
    public User getUserByAccount(String account) {
        User user = super.getOne(new QueryWrapper<User>().eq("account",account));
        return user;
    }

    @Override
    public JSONObject login(User user) {
        String account = user.getAccount();
        String password = PasswordUtil.encode(user.getPassword());
        User userPo;
        //判断是否是邮箱登录，注册时已经限制了不能有特殊字符，所以不存在账户名包括@字符
        if (account.contains("@")){
            userPo =  super.getOne(new QueryWrapper<User>().eq("mail",account));
        }else{
            userPo =  super.getOne(new QueryWrapper<User>().eq("account",account));
        }
        if (userPo==null){
            throw new BizException("用户不存在");
        }
        if (!password.equals(userPo.getPassword())){
            throw new BizException("密码错误");
        }
        userPo.setPassword(null);
        // 生成token
        String token = JwtUtil.sign(account, password);
        redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
        // 设置超时时间
        redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME);
        // 获取用户部门信息
        JSONObject obj = new JSONObject();
        obj.put("token", token);
        obj.put("userInfo", userPo);
        obj.put("operations",operationService.getOperationsByIds(uOperationService.getUOperationByUId(userPo.getUserId())));
        return obj;
    }

    @Override
    public int loginOut(String token) {
        redisUtil.del(CommonConstant.PREFIX_USER_TOKEN + token);
        return 1;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public int insertUser(UserVo user) {
        log.info("正在插入user");
        //检验注册账号是否含有特殊字符
        if (!CommonUtils.isAlphaNumeric(user.getAccount())){
            throw new BizException("注册账户含有特殊字符，注册失败");
        }
        if (super.getOne(new QueryWrapper<User>().eq("account",user.getAccount()))!=null){
            throw new BizException("此用户名已存在，请重新注册");
        }
        String code = String.valueOf(redisUtil.get(MailPre.REGISTER+user.getMail()));
        if (code!=null&&redisUtil.getExpire(MailPre.REGISTER+user.getMail())>0&&user.getCode().equals(code)){
            user.setPassword(PasswordUtil.encode(user.getPassword()));
            if (user.getIntro() == null){
                user.setIntro("暂未填写");
            }
            if (user.getNickname()==null){
                user.setNickname(user.getAccount());
            }
            if (super.save(user)) {
                redisUtil.del(MailPre.REGISTER+user.getMail());
                log.info("插入user成功,id为{}",user.getUserId());
                //发送消息
                Information information = new Information();
                information.setUserId(user.getUserId());
                information.setMessage("尊敬的用户您好，您已成功注册成果管理系统\n您可以通过用户认证获得系统的更多使用权限。");
                informationService.insertInformation(information);
                return user.getUserId();
            } else {
                log.error("插入user失败");
                throw new BizException("添加失败");
            }
        }else {
            log.info("验证邮箱{}验证码错误，注册失败",user.getMail());
            throw new BizException("验证邮箱验证码错误，注册失败");
        }
    }

    @Override
    public int normalInsertUser(User user) {
        log.info("正在插入user");
        //检验注册账号是否含有特殊字符
        if (!CommonUtils.isAlphaNumeric(user.getAccount())){
            throw new BizException("注册账户含有特殊字符，注册失败");
        }
        if (super.getOne(new QueryWrapper<User>().eq("account",user.getAccount()))!=null){
            throw new BizException("此用户名已存在，请重新注册");
        }
        user.setIntro("暂未填写");
        if (user.getNickname()==null){
            user.setNickname(user.getAccount());
        }
        if (super.save(user)) {
            log.info("插入user成功,id为{}",user.getUserId());
            //发送消息
            Information information = new Information();
            information.setUserId(user.getUserId());
            information.setMessage("尊敬的用户您好，您已成功注册成果管理系统\n您可以通过用户认证获得系统的更多使用权限。");
            informationService.insertInformation(information);
            return user.getUserId();
        } else {
            log.error("插入user失败");
            throw new BizException("添加失败");
        }
    }

    @Transactional
    @Override
    public int deleteUserById(int id) {
        log.info("正在删除id为{}的user",id);
        if (super.removeById(id)) {
            log.info("删除id为{}的user成功",id);
            return id;
        } else {
            log.error("删除id为{}的user失败",id);
            throw new BizException("删除失败[id=" + id + "]");
        }
    }

    @Transactional
    @Override
    public int updateUser(User user) {
        log.info("正在更新id为{}的user",user.getUserId());
        //有修改头像
        if (user.getPhoto()!=null){
            String oldPhoto = super.getById(user.getUserId()).getPhoto();
            //删除旧头像
            if (oldPhoto!=null){
                String filePath=path+"user/"+oldPhoto.substring(oldPhoto.lastIndexOf("/")+1);
                log.info("删除id为{}的用户的旧头像",user.getUserId());
                FileUtils.deleteFile(filePath);
            }
        }
        if (super.updateById(user)) {
            log.info("更新id为{}的user成功",user.getUserId());
            return user.getUserId();
        } else {
            log.error("更新id为{}的user失败",user.getUserId());
            throw new BizException("更新失败[id=" + user.getUserId() + "]");
        }
    }

    @Override
    public boolean sendMail(String pre,String mail) {
        log.info("正在发送邮件到邮箱{}",mail);
        User userPo = super.getOne(new QueryWrapper<User>().eq("mail",mail));
        //当发送邮箱是注册或重置邮箱时，此邮箱不能被注册，确保邮箱绑定一个账户
        if (pre.equals(MailPre.REGISTER)||pre.equals(MailPre.RESET_MAIL)){
            if (userPo!=null){
                throw new BizException("此邮箱在此系统已被绑定注册，请输入未被绑定过的邮箱");
            }
        }
        String  code = RandomCodeUtils.getRandomCode();
        String subject="成果管理系统";
        String context="尊敬的用户你好"+
                "你的验证码是:"+
                code+"\n你可以用这个验证码进行注册、修改你的绑定邮箱或者忘记密码验证,有效期为五分钟。如果不是你的本人操作请忽略此条信息！";
        if (mailService.sendMail(mail,subject,context)){
            redisUtil.set(pre+mail,code,300);
            log.info("发送邮件到邮箱{}成功",mail);
            return true;
        }
        log.error("发送邮件到邮箱{}失败",mail);
        return false;
    }

    @Override
    public int resetMail(UserVo user) {
        log.info("正在更新id为{}的邮箱",user.getUserId());
        String code = (String) redisUtil.get(MailPre.RESET_MAIL+user.getMail());
        if (code!=null&&redisUtil.getExpire(MailPre.RESET_MAIL+user.getMail())>0&&user.getCode().equals(code)){
            if (super.updateById(user)) {
                log.info("更新id为{}的邮箱成功",user.getUserId());
                redisUtil.del(MailPre.RESET_MAIL+user.getMail());
                return user.getUserId();
            } else {
                log.error("更新id为{}的邮箱失败",user.getUserId());
                throw new BizException("更新失败[id=" + user.getUserId() + "]");
            }
        }else {
            log.info("验证邮箱{}验证码错误，修改邮箱失败",user.getMail());
            throw new BizException("验证邮箱验证码错误，修改邮箱失败");
        }
    }

    @Override
    public int resetPwd(User user,String oldPwd,String newPwd) {
        log.info("正在更新id为{}的密码",user.getUserId());
        if (user.getPassword().equals(PasswordUtil.encode(oldPwd))){
            User userPo = new User();
            userPo.setUserId(user.getUserId());
            userPo.setPassword(PasswordUtil.encode(newPwd));
            if (super.updateById(userPo)) {
                log.info("更新id为{}的用户的密码成功",user.getUserId());
                return user.getUserId();
            } else {
                log.error("更新id为{}的用户的密码失败",user.getUserId());
                throw new BizException("更新失败[id=" + user.getUserId() + "]");
            }
        }else{
            throw new BizException("更新失败,请确认输入的旧密码是否正确");
        }
    }


    @Override
    public int forgetPwd(UserVo user) {
        log.info("account为{}的用户正在忘记密码",user.getAccount());
        User userPo = super.getOne(new QueryWrapper<User>().eq("mail",user.getMail()));
        user.setUserId(userPo.getUserId());
        user.setPassword(PasswordUtil.encode(user.getPassword()));
        String code = (String) redisUtil.get(MailPre.RESET_PWD+user.getMail());
        if (code!=null&&redisUtil.getExpire(MailPre.RESET_PWD+user.getMail())>0&&user.getCode().equals(code)){
            if (super.updateById(user)) {
                log.info("更新id为{}的用户的密码成功",user.getUserId());
                redisUtil.del(MailPre.RESET_PWD+user.getMail());
                return user.getUserId();
            } else {
                log.error("更新id为{}的用户的密码失败",user.getUserId());
                throw new BizException("更新失败[id=" + user.getUserId() + "]");
            }
        }else {
            log.info("验证邮箱{}验证码错误",user.getMail());
            throw new BizException("验证邮箱验证码错误");
        }
    }

    @Override
    public int teamAuthenticate(User user) {
        log.info("id为{}的user正在进行团队认证",user.getUserId());
        if (super.updateById(user)) {
            log.info("更新id为{}的user成功",user.getUserId());
            return user.getUserId();
        } else {
            log.error("更新id为{}的user失败",user.getUserId());
            throw new BizException("更新失败[id=" + user.getUserId() + "]");
        }
    }

    @Override
    public int firmAuthenticate(User user) {
        log.info("id为{}的user正在进行企业认证",user.getUserId());
        if (super.updateById(user)) {
            log.info("更新id为{}的user成功",user.getUserId());
            return user.getUserId();
        } else {
            log.error("更新id为{}的user失败",user.getUserId());
            throw new BizException("更新失败[id=" + user.getUserId() + "]");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public int checkTeam(int id, Boolean flag) {
        log.info("正在审核id为{}的user的团队认证",id);
        User user = new User();
        user.setUserId(id);
        //发送消息
        Information information = new Information();
        information.setTime(LocalDateTime.now());
        information.setUserId(id);
        if (flag){
            information.setMessage("尊敬的用户您好，您的团队认证审核已通过。");
            user.setTeamState(User.TEAM_PASS);
        }else{
            information.setMessage("尊敬的用户您好，您的团队认证审核未通过，您可以对团队信息进行修改后再次提交申请。");
            user.setTeamState(User.TEAM_NO_PASS);
        }
        if (super.updateById(user)) {
            informationService.insertInformation(information);
            log.info("更新id为{}的user成功，审核结果为{}",user.getUserId(),flag);
            return user.getUserId();
        } else {
            log.error("更新id为{}的user失败",user.getUserId());
            throw new BizException("更新失败[id=" + user.getUserId() + "]");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public int checkFirm(int id, Boolean flag) {
        log.info("正在审核id为{}的user的企业认证",id);
        User user = new User();
        user.setUserId(id);
        Information information = new Information();
        information.setUserId(id);
        information.setTime(LocalDateTime.now());
        if (flag){
            information.setMessage("尊敬的用户您好，您的企业认证审核已通过。");
            user.setFirmState(User.FIRM_PASS);
        }else{
            information.setMessage("尊敬的用户您好，您的企业认证审核未通过，您可以对企业信息进行修改后再次提交申请。");
            user.setFirmState(User.FIRM_NO_PASS);
        }
        if (super.updateById(user)) {
            log.info("更新id为{}的user成功，审核结果为{}",user.getUserId(),flag);
            informationService.insertInformation(information);
            return user.getUserId();
        } else {
            log.error("更新id为{}的user失败",user.getUserId());
            throw new BizException("更新失败[id=" + user.getUserId() + "]");
        }
    }

    @Override
    public User getByQueryWrapper(Wrapper<User> queryWrapper){
        return super.getOne(queryWrapper);
    }
}
